#include "AutoSaver.h"

#include "BookmarksManager.h"
#include "BookmarksModel.h"
#include "BookmarkNode.h"

#include "InsertBookmarksCommand.h"
#include "ChangeBookmarkCommand.h"

#include "XbelReader.h"
#include "XbelWriter.h"

#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>

BookmarksManager::BookmarksManager(QObject *parent)
    : QObject(parent)
    , m_loaded(false)
    , m_saveTimer(new AutoSaver(this))
    , m_bookmarkRootNode(0)
    , m_bookmarkModel(0)
{
    connect(this, SIGNAL(entryAdded(BookmarkNode *)),
            m_saveTimer, SLOT(changeOccurred()));
    connect(this, SIGNAL(entryRemoved(BookmarkNode *, int, BookmarkNode *)),
            m_saveTimer, SLOT(changeOccurred()));
    connect(this, SIGNAL(entryChanged(BookmarkNode *)),
            m_saveTimer, SLOT(changeOccurred()));
}

BookmarksManager::~BookmarksManager()
{
    m_saveTimer->saveIfNeccessary();
}

void BookmarksManager::changeExpanded()
{
    m_saveTimer->changeOccurred();
}

void BookmarksManager::load()
{
    if (m_loaded)
        return;
    m_loaded = true;

    QString dir = "data/";  /*BrowserApplication::dataLocation()*/
    QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel");
    if (!QFile::exists(bookmarkFile))
#ifdef WINPE
        bookmarkFile = QLatin1String(":defaultbookmarks_winpe.xbel");
#else
        bookmarkFile = QLatin1String(":defaultbookmarks.xbel");
#endif

    XbelReader reader;
    m_bookmarkRootNode = reader.read(bookmarkFile);
    if (reader.error() != QXmlStreamReader::NoError)
    {
        QMessageBox::warning(0, tr("Loading Bookmark"), tr("Error when loading bookmarks on line %1, column %2:\n"
                                "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
    }

    BookmarkNode *toolbar = 0;
    BookmarkNode *menu = 0;
    QList<BookmarkNode*> others;
    for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i)
    {
        BookmarkNode *node = m_bookmarkRootNode->children().at(i);
        if (node->type() == BookmarkNode::Folder)
        {
            // Automatically convert
            if (node->title == ("Панель \"Закладки\"") && !toolbar)
            {
                node->title = tr("Панель \"Закладки\"");
            }

            if (node->title == tr("Панель \"Закладки\"") && !toolbar)
            {
                toolbar = node;
            }

            // Automatically convert
            if (node->title == ("Меню \"Закладки\"") && !menu)
            {
                node->title = tr("Меню \"Закладки\"");
            }
            if (node->title == tr("Меню \"Закладки\"") && !menu)
            {
                menu = node;
            }
        }
        else
        {
            others.append(node);
        }
        m_bookmarkRootNode->remove(node);
    }

    Q_ASSERT(m_bookmarkRootNode->children().count() == 0);
    if (!toolbar) {
        toolbar = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
        toolbar->title = tr("Панель \"Закладки\"");
    } else
    {
        m_bookmarkRootNode->add(toolbar);
    }

    if (!menu)
    {
        menu = new BookmarkNode(BookmarkNode::Folder, m_bookmarkRootNode);
        menu->title = tr("Меню \"Закладки\"");
    } else
    {
        m_bookmarkRootNode->add(menu);
    }

    for (int i = 0; i < others.count(); ++i)
        menu->add(others.at(i));
}

void BookmarksManager::save() const
{
    if (!m_loaded)
        return;

    XbelWriter writer;
    QString dir = "data/" /*BrowserApplication::dataLocation()*/;
    QString bookmarkFile = dir + QLatin1String("/bookmarks.xbel");
    if (!writer.write(bookmarkFile, m_bookmarkRootNode))
        qWarning() << "BookmarkManager: error saving to" << bookmarkFile;
}

void BookmarksManager::addBookmark(BookmarkNode *parent, BookmarkNode *node, int row)
{
    if (!m_loaded)
        return;
    Q_ASSERT(parent);
    InsertBookmarksCommand *command = new InsertBookmarksCommand(this, parent, node, row);
    m_commands.push(command);
}

void BookmarksManager::removeBookmark(BookmarkNode *node)
{
    if (!m_loaded)
        return;

    Q_ASSERT(node);
    BookmarkNode *parent = node->parent();
    int row = parent->children().indexOf(node);
    RemoveBookmarksCommand *command = new RemoveBookmarksCommand(this, parent, row);
    m_commands.push(command);
}

void BookmarksManager::setTitle(BookmarkNode *node, const QString &newTitle)
{
    if (!m_loaded)
        return;

    Q_ASSERT(node);
    ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newTitle, changedTitle);
    m_commands.push(command);
}

void BookmarksManager::setUrl(BookmarkNode *node, const QString &newUrl)
{
    if (!m_loaded)
        return;

    Q_ASSERT(node);
    ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newUrl, changedURL);
    m_commands.push(command);
}

void BookmarksManager::setTags(BookmarkNode *node, const QString &newTags)
{
    if (!m_loaded)
        return;

    Q_ASSERT(node);
    ChangeBookmarkCommand *command = new ChangeBookmarkCommand(this, node, newTags, changedTags);
    m_commands.push(command);
}

BookmarkNode *BookmarksManager::bookmarks()
{
    if (!m_loaded)
        load();
    return m_bookmarkRootNode;
}

BookmarkNode *BookmarksManager::menu()
{
    if (!m_loaded)
        load();

    for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
        BookmarkNode *node = m_bookmarkRootNode->children().at(i);
        if (node->title == tr("Меню \"Закладки\""))
            return node;
    }
    Q_ASSERT(false);
    return 0;
}

BookmarkNode *BookmarksManager::toolbar()
{
    if (!m_loaded)
        load();

    for (int i = m_bookmarkRootNode->children().count() - 1; i >= 0; --i) {
        BookmarkNode *node = m_bookmarkRootNode->children().at(i);
        if (node->title == tr("Панель \"Закладки\""))
            return node;
    }
    Q_ASSERT(false);
    return 0;
}
QStringList BookmarksManager::find_tag_urls(BookmarkNode *start_node, const QString& tag)
{
    if (!m_loaded)
        load();

    if (!start_node)
        start_node = m_bookmarkRootNode;

    QStringList tags;

    for (int i = start_node->children().count() - 1; i >= 0; --i) {
        BookmarkNode *node = start_node->children().at(i);
        if (node)
        {
            if (node->type() == BookmarkNode::Bookmark)
            {
                QStringList node_tags = node->tags.split(QRegExp("\\W+"), QString::SkipEmptyParts);
                foreach(QString node_tag, node_tags)
                {
                    if (tag.toLower() == node_tag.toLower())
                    {
                        tags.append(node->url);
                        break;
                    }
                }
            }
            if (node->type() == BookmarkNode::Folder)
            {
                tags += find_tag_urls(node, tag);
            }
        }
    }

    return tags;
}

BookmarkNode *BookmarksManager::find_folder(BookmarkNode *start_node,const QString& title)
{
   if (!m_loaded)
        load();

    if (!start_node)
        start_node = m_bookmarkRootNode;

    for (int i = start_node->children().count() - 1; i >= 0; --i) {
        BookmarkNode *node = start_node->children().at(i);
        if (node && node->title == title && node->type() == BookmarkNode::Folder)
            return node;
        if (node && node->type() == BookmarkNode::Folder)
        {
            BookmarkNode *found_node = find_folder(node, title);
            if (found_node)
                return found_node;
        }
    }
    return 0;
}

BookmarksModel *BookmarksManager::bookmarksModel()
{
    if (!m_bookmarkModel)
        m_bookmarkModel = new BookmarksModel(this, this);
    return m_bookmarkModel;
}

void BookmarksManager::importFromIE()
{
//    BookmarkNode *importRootNode = BookmarksImport::importFromIE();
//    if (importRootNode)
//    {
//        importRootNode->setType(BookmarkNode::Folder);
//        importRootNode->title = (tr("Imported %1 from Internet Explorer").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate)));
//        addBookmark(menu(), importRootNode);
//        QMessageBox::information(0, tr("Importing Bookmarks"),
//            tr("Successfully imported Microsoft Internet Explorer favorites."));
//    }
}

void BookmarksManager::importFromMozilla()
{
//    QString path = BookmarksImport::mozillaPath();
//    if (path.isEmpty())
//    {
//        QMessageBox::warning(0, tr("Importing Bookmarks"),
//            tr("Mozilla FireFox local profile location is not found.<br>Please find and import BOOKMARKS.HTML file manually."));
//        return;
//    }
//    BookmarkNode *importRootNode = BookmarksImport::importFromHtml( path );
//    if (importRootNode)
//    {
//        importRootNode->setType(BookmarkNode::Folder);
//        importRootNode->title = (tr("Imported %1 from Mozilla FireFox").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate)));
//        addBookmark(menu(), importRootNode);
//        QMessageBox::information(0, tr("Importing Bookmarks"),
//            tr("Successfully imported Mozilla FireFox bookmarks."));
//    }
}

void BookmarksManager::importFromHTML()
{
//    QString fileName = QFileDialog::getOpenFileName(0, tr("Open File"),
//                                                     QString(),
//                                                     tr("Netscape HTML Bookmarks (*.html;*.htm)"));
//    if (fileName.isEmpty())
//        return;

//    BookmarkNode *importRootNode = BookmarksImport::importFromHtml( fileName );

//    if (importRootNode)
//    {
//        importRootNode->setType(BookmarkNode::Folder);
//        importRootNode->title = (tr("Imported %1 from HTML").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate)));
//        addBookmark(menu(), importRootNode);
//        QMessageBox::information(0, tr("Importing Bookmarks"),
//            tr("Successfully imported bookmarks from Netscape defined HTML file."));
//    }
}

void BookmarksManager::importBookmarks()
{
//    QString fileName = QFileDialog::getOpenFileName(0, tr("Open File"),
//                                                     QString(),
//                                                     tr("XBEL (*.xbel *.xml)"));
//    if (fileName.isEmpty())
//        return;

//    XbelReader reader;
//    BookmarkNode *importRootNode = reader.read(fileName);
//    if (reader.error() != QXmlStreamReader::NoError) {
//        QMessageBox::warning(0, tr("Loading Bookmark"),
//            tr("Error when loading bookmarks on line %1, column %2:\n"
//               "%3").arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()));
//    }

//    importRootNode->setType(BookmarkNode::Folder);
//    importRootNode->title = (tr("Imported %1").arg(QDate::currentDate().toString(Qt::SystemLocaleShortDate)));
//    addBookmark(menu(), importRootNode);
}

void BookmarksManager::exportBookmarks()
{
//    QString fileName = QFileDialog::getSaveFileName(0, tr("Save File"),
//                                QString("%1 Bookmarks.xbel").arg(QCoreApplication::applicationName()),
//                                QString("XBEL (*.xbel *.xml)"));
//    if (fileName.isEmpty())
//        return;

//    XbelWriter writer;
//    if (!writer.write(fileName, m_bookmarkRootNode))
//        QMessageBox::critical(0, tr("Export error"), tr("error saving bookmarks"));
}
